package reesoft.common.util;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.time.FastDateFormat;

import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.Date;

/**
 * 公用数据类型转换单元
 *
 * Created by reesoft on 2017-07-13
 */
public class ConvertUtil
{
    private final static String DEFAULT_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

    /**
     * 从字符串解析出整数
     *
     * @return 解析成功的整数；如果解析失败，返回 null
     */
    public static Integer stringToInteger(final String string)
    {
        return stringToInteger(string, null);
    }

    /**
     * 从字符串解析出整数
     *
     * @return 解析成功的整数；如果解析失败，返回 null
     */
    public static Integer stringToInteger(final String string, Integer defaultValue)
    {
        try
        {
            return Integer.valueOf(string);
        }
        catch (NullPointerException | NumberFormatException e)
        {
            return defaultValue;
        }
    }

    /**
     * 从字符串解析出整型数组
     *
     * @param delimiter 分隔数字的符号
     * @return 解析成功的整数数组；数组元素 null 值表示解析失败
     */
    public static Integer[] stringToIntegerArray(final String string, final String delimiter)
    {
        if (StringUtil.isEmpty(string))
        {
            return new Integer[0];
        }

        String[] stringArrayValue = string.split(delimiter);

        Integer[] integerArrayValue = new Integer[stringArrayValue.length];
        int index = 0;

        for (String stringValue : stringArrayValue)
        {
            integerArrayValue[index] = stringToInteger(stringValue, null);
            index++;
        }

        return integerArrayValue;
    }

    /**
     * 从字符串解析出长整数
     *
     * @return 解析成功的长整数；如果解析失败，返回 null
     */
    public static Long stringToLong(final String string)
    {
        return stringToLong(string, null);
    }

    /**
     * 从字符串解析出长整数
     *
     * @return 解析成功的长整数；如果解析失败，返回 null
     */
    public static Long stringToLong(final String string, final Long defaultValue)
    {
        try
        {
            return Long.valueOf(string);
        }
        catch (NullPointerException | NumberFormatException e)
        {
            return defaultValue;
        }
    }

    /**
     * 从字符串解析出长整型数组
     *
     * @param delimiter 分隔数字的符号
     * @return 解析成功的长整数数组；数组元素 null 值表示解析失败
     */
    public static Long[] stringToLongArray(final String string, final String delimiter)
    {
        if (StringUtil.isEmpty(string))
        {
            return new Long[0];
        }

        String[] stringArrayValue = string.split(delimiter);

        Long[] longArrayValue = new Long[stringArrayValue.length];
        int index = 0;

        for (String stringValue : stringArrayValue)
        {
            longArrayValue[index] = stringToLong(stringValue, null);
            index++;
        }

        return longArrayValue;
    }

    /**
     * 从字符串解析出单精度浮点数
     *
     * @return 解析成功的单精度浮点数；如果解析失败，返回 null
     */
    public static Float stringToFloat(final String string)
    {
        return stringToFloat(string, null);
    }

    /**
     * 从字符串解析出单精度浮点数
     *
     * @return 解析成功的单精度浮点数；如果解析失败，返回 null
     */
    public static Float stringToFloat(final String string, final Float defaultValue)
    {
        try
        {
            return Float.valueOf(string);
        }
        catch (NullPointerException | NumberFormatException e)
        {
            return defaultValue;
        }
    }

    /**
     * 从字符串解析出双精度浮点数
     *
     * @return 解析成功的双精度浮点数；如果解析失败，返回 null
     */
    public static Double stringToDouble(final String string)
    {
        return stringToDouble(string, null);
    }

    /**
     * 从字符串解析出双精度浮点数
     *
     * @return 解析成功的双精度浮点数；如果解析失败，返回 null
     */
    public static Double stringToDouble(final String string, final Double defaultValue)
    {
        try
        {
            return Double.valueOf(string);
        }
        catch (NullPointerException | NumberFormatException e)
        {
            return defaultValue;
        }
    }

    /**
     * 转换字符串为字节数组
     *
     * @return 字节数组，转换失败时返回 null
     */
    public static byte[] stringToBytes(final String string)
    {
        if (string != null)
        {
            try
            {
                return string.getBytes("UTF-8");
            }
            catch (UnsupportedEncodingException e)
            {
                return null;
            }
        }
        else
        {
            return null;
        }
    }

    /**
     * 转换字符串为 boolean 类型
     * 'true', 'on', 'y', 't', 'yes' or '1' (case insensitive) will return true. otherwise return false.
     */
    public static boolean stringToBoolean(final String string)
    {
        return stringToBoolean(string, Boolean.FALSE);
    }

    /**
     * 转换字符串为 Boolean 类型
     * 'true', 'on', 'y', 't', 'yes' or '1' (case insensitive) will return Boolean.TRUE.
     * 'false', 'off', 'n', 'f', 'no' or '0' (case insensitive) will return Boolean.FALSE.
     */
    public static Boolean stringToBoolean(final String string, Boolean defaultValue)
    {
        Boolean value = BooleanUtils.toBooleanObject(string);

        if (value != null)
        {
            return value;
        }
        else if ("1".equals(string))
        {
            return Boolean.TRUE;
        }
        else if ("0".equals(string))
        {
            return Boolean.FALSE;
        }
        else
        {
            return defaultValue;
        }
    }

    /**
     * 按缺省格式（yyyy-MM-dd HH:mm:ss）从字符串解析出日期
     *
     * @return 解析成功的日期；如果解析失败，返回 null
     */
    public static Date stringToDate(final String string)
    {
        return stringToDate(string, DEFAULT_TIME_FORMAT, null);
    }

    /**
     * 按指定格式从字符串解析出日期
     *
     * @return 解析成功的日期；如果解析失败，返回 null
     */
    public static Date stringToDate(final String string, final String pattern, final Date defaultValue)
    {
        try
        {
            // 用 Apache FastDateFormat 替代 SimpleDateFormat 解析日期，速度更快，且线程安全
            return FastDateFormat.getInstance(pattern).parse(string);
        }
        catch (NullPointerException | ParseException e)
        {
            return defaultValue;
        }
    }

    /**
     * 把日期转换成缺省格式（yyyy-MM-dd HH:mm:ss）的字符串
     *
     * @return 日期字符串，如果日期参数值无效，返回 null
     */
    public static String dateToString(final Date date)
    {
        return dateToString(date, DEFAULT_TIME_FORMAT);
    }

    /**
     * 把日期转换成指定格式的字符串
     *
     * @return 日期字符串，如果日期或格式参数值无效，返回 null
     */
    public static String dateToString(final Date date, final String pattern)
    {
        if (date == null || pattern == null || pattern.isEmpty())
        {
            return null;
        }

        // 用 Apache FastDateFormat 替代 SimpleDateFormat 格式化日期，速度更快，且线程安全
        return FastDateFormat.getInstance(pattern).format(date);
    }

    /**
     * 把时间戳（精确到毫秒）转换成指定格式的字符串
     *
     * @return 日期字符串，如果时间戳或格式参数值无效，返回 null
     */
    public static String timestampToString(final Long timestamp, final String pattern)
    {
        if (timestamp == null)
        {
            return null;
        }

        return dateToString(new Date(timestamp), pattern);
    }

    /**
     * 转换字节数组为字符串
     *
     * @return 字符串，转换失败时返回空字符串
     */
    public static String toString(final byte[] bytes)
    {
        try
        {
            return new String(bytes, "UTF-8");
        }
        catch (UnsupportedEncodingException e)
        {
            return "";
        }
    }

    /**
     * 转换字节数组为 16 进制字符串
     *
     * @return 字符串
     */
    public static String toHexString(final byte[] bytes)
    {
        StringBuilder stringBuilder = new StringBuilder();

        for (byte b : bytes)
        {
            int bt = b & 0xff;
            if (bt < 16)
            {
                stringBuilder.append(0);
            }

            stringBuilder.append(Integer.toHexString(bt));
        }

        return stringBuilder.toString();
    }

    /**
     * 转换对象为字符串，如果对象为空则返回 defaultValue
     *
     * @param object 要转换的对象
     * @param defaultValue 缺省值
     * @return 字符串
     */
    public static String toString(final Object object, final String defaultValue)
    {
        return object == null ? defaultValue : object.toString();
    }
}
